home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Almathera Ten Pack 3: CDPD 3
/
Almathera Ten on Ten - Disc 3: CDPD3.iso
/
fish
/
001-100
/
001-025
/
022
/
pemacs
/
word.c
< prev
Wrap
C/C++ Source or Header
|
1995-03-17
|
14KB
|
475 lines
/*
* The routines in this file implement commands that work word at a time.
* There are all sorts of word mode commands. If I do any sentence and/or
* paragraph mode commands, they are likely to be put in this file.
*/
#include <stdio.h>
#include "ed.h"
#define WPNULL -1 /* null word pointer */
/* Paragraph fill. Retain indenting of first line of paragraph. Remove
* leading spaces from other lines. Remove extra space between words.
* Fill each line to fillcol, breaking at word boundaries.
* Delete trailing space from all lines.
*/
parafill( f, n)
{
register int c; /* current char */
register short spo; /* space offset */
register short count;
short wo; /* word offset */
WINDOW *wp;
LINE *flp, /* first line of paragraph */
*clp; /* current line of paragraph */
/* save old context */
/* we do this by creating a fake window which retains the context.
* this will be updated by the editing commands.
*/
if ((wp = (WINDOW *) malloc(sizeof(WINDOW))) == NULL) {
mlwrite("Cannot allocate WINDOW block");
return (FALSE);
}
wp->w_bufp = curbp;
wp->w_dotp = curwp->w_dotp;
wp->w_doto = curwp->w_doto;
wp->w_markp = curwp->w_markp;
wp->w_marko = curwp->w_marko;
wp->w_flag = 0;
wp->w_force = 0;
wp->w_wndp = wheadp;
wheadp = wp;
/* get first line of paragraph */
for( flp = curwp->w_dotp; flp != curbp->b_linep; flp = lback( flp)) {
if( llength( flp) == 0) /* blank line, found it */
break;
}
flp = lforw( flp);
if( llength( flp) == 0) /* nothing to do */
return( TRUE);
/* initialize */
count = 0;
curwp->w_dotp = clp = flp;
for(;;) { /* go through all lines */
spo = count; /* set space offset at current spot */
/* get to end of spaces */
for( ;; count++) {
c = wgetc( &clp, count);
if( (c != ' ') || (c == EOF)) break;
}
wo = count;
/* get to end of word */
for( ;; count++) {
c = wgetc( &clp, count);
if( (c == ' ') || (c == EOF)) break;
}
if(((clp != flp) || spo) && (spo != wo)) {
/* adjust spaces. if at beginning of line, delete all spaces */
curwp->w_doto = spo;
if( spo) { /* past begin of line */
count += adjsp( &clp, spo, &wo);
} else { /* at begin of line */
ldelete( wo - spo, FALSE);
wo = count = 0;
}
}
if( count > fillcol) { /* if past fill column, break. */
if(((clp != flp) || spo) && (spo != wo)) {
/* collapse the spaces */
curwp->w_doto = spo;
ldelete( wo - spo, FALSE);
wo = spo;
}
if( wo > 0) { /* break at beginning of word */
curwp->w_doto = wo;
} else { /* break at end of word */
curwp->w_doto = count;
}
newline( FALSE, 1);
count = 0;
clp = curwp->w_dotp; /* updated by newline */
}
if( c == EOF) break;
}
/* restore context and delete fake window */
curwp->w_dotp = wp->w_dotp;
curwp->w_doto = wp->w_doto;
curwp->w_markp = wp->w_markp;
curwp->w_marko = wp->w_marko;
wheadp = wp->w_wndp;
free( (char *) wp);
return( TRUE);
}
/* adjust the spacing between words. check for colons and periods.
* assumes spo > 0 and doto is set to spo.
*/
adjsp( lp, spo, wo)
register LINE **lp;
register short spo, *wo;
{
short result, spaces, n, c;
/* decide on number of spaces */
switch( lgetc( *lp, spo -1)) {
case ':':
spaces = 2;
break;
case '.':
spaces = 1; /* just a guess */
n = spo -2;
if( n == 0) /* period at beginning of line */
break;
else {
c = lgetc( *lp, n);
if((('a' <= c) && (c <= 'z'))
|| (('A' <= c) && (c <= 'Z'))) { /* letter */
n -= 1;
if( n == 0) /* single letter followed by . */
break;
else {
c = lgetc( *lp, n);
if((c == ' ')
|| (c == '.'))/* single letter followed by . */
break;
}
} else /* not a letter */
break;
}
if( *wo < llength( *lp)) {
c = lgetc( *lp, *wo);
if((c < 'A') || ('Z' < c)) /* not a cap letter */
break;
}
spaces = 2;
break;
default:
spaces = 1;
break;
}
/* adjust them */
if( (*wo - spo) == spaces) /* perfect */
return( 0);
else if( (*wo - spo) > spaces) { /* delete extras */
result = *wo - spo - spaces;
ldelete( result, FALSE);
result = - result;
} else { /* pad with spaces */
result = spaces - (*wo - spo);
linsert( result, ' ');
}
*lp = curwp->w_dotp;
*wo = spo + spaces;
return( result);
}
/* Get next char, word-oriented style. If at end of line, append next
* line by replacing newline with a space. Return EOF
* when there is nothing left.
*/
wgetc( clp, n)
LINE **clp;
int n;
{
LINE *newlp;
if( n > llength( *clp)) {
mlwrite( "Bad para fill");
return( EOF);
}
if( n == llength( *clp)) {
newlp = lforw( *clp);
if( llength( newlp) == 0) return( EOF);
curwp->w_doto = n;
ldelete( 1, FALSE);
linsert( 1, ' ');
*clp = curwp->w_dotp;
}
return( lgetc( *clp, n));
}
/* Break line on spaces. Back-over whatever precedes the point on the current
* line and stop on the first space or the beginning of the line. If we
* reach the beginning of the line, do nothing.
* Otherwise, break the line at the space, eat previous spaces, and jump
* back to the end of the word.
* Returns TRUE on success, FALSE on errors.
*/
wrapword()
{
register int wo, spo, oldo;
LINE *oldp;
oldp = curwp->w_dotp;
oldo = curwp->w_doto;
for( spo = oldo; spo > 0; --spo) {
if( lgetc( oldp, spo) == ' ') break;
}
if( spo) wo = spo + 1; /* wo points at start of word */
else /* can't do it */
return( FALSE);
for( ; spo > 0; --spo) {
if( lgetc( oldp, spo) != ' ') break;
}
if( spo) spo = spo + 1; /* spo points at start of spaces */
else /* can't do it */
return( FALSE);
/* delete spaces and insert new line */
curwp->w_doto = spo;
forwdel( FALSE, wo - spo);
newline( FALSE, 1);
if( oldo > spo) /* adjust point */
curwp->w_doto = oldo - wo;
return( TRUE);
}
/*
* Move the cursor backward by "n" words. All of the details of motion are
* performed by the "backchar" and "forwchar" routines. Error if you try to
* move beyond the buffers.
*/
backword(f, n)
{
if (n < 0)
return (forwword(f, -n));
if (backchar(FALSE, 1) == FALSE)
return (FALSE);
while (n--) {
while (inword() == FALSE) {
if (backchar(FALSE, 1) == FALSE)
return (FALSE);
}
while (inword() != FALSE) {
if (backchar(FALSE, 1) == FALSE)
return (FALSE);
}
}
return (forwchar(FALSE, 1));
}
/*
* Move the cursor forward by the specified number of words. All of the motion
* is done by "forwchar". Error if you try and move beyond the buffer's end.
*/
forwword(f, n)
{
if (n < 0)
return (backword(f, -n));
while (n--) {
while (inword() == FALSE) {
if (forwchar(FALSE, 1) == FALSE)
return (FALSE);
}
while (inword() != FALSE) {
if (forwchar(FALSE, 1) == FALSE)
return (FALSE);
}
}
return (TRUE);
}
/*
* Move the cursor forward by the specified number of words. As you move,
* convert any characters to upper case. Error if you try and move beyond the
* end of the buffer. Bound to "M-U".
*/
upperword(f, n)
{
register int c;
if (n < 0)
return (FALSE);
while (n--) {
while (inword() == FALSE) {
if (forwchar(FALSE, 1) == FALSE)
return (FALSE);
}
while (inword() != FALSE) {
c = lgetc(curwp->w_dotp, curwp->w_doto);
if (c>='a' && c<='z') {
c -= 'a'-'A';
lputc(curwp->w_dotp, curwp->w_doto, c);
lchange(WFHARD);
}
if (forwchar(FALSE, 1) == FALSE)
return (FALSE);
}
}
return (TRUE);
}
/*
* Move the cursor forward by the specified number of words. As you move
* convert characters to lower case. Error if you try and move over the end of
* the buffer. Bound to "M-L".
*/
lowerword(f, n)
{
register int c;
if (n < 0)
return (FALSE);
while (n--) {
while (inword() == FALSE) {
if (forwchar(FALSE, 1) == FALSE)
return (FALSE);
}
while (inword() != FALSE) {
c = lgetc(curwp->w_dotp, curwp->w_doto);
if (c>='A' && c<='Z') {
c += 'a'-'A';
lputc(curwp->w_dotp, curwp->w_doto, c);
lchange(WFHARD);
}
if (forwchar(FALSE, 1) == FALSE)
return (FALSE);
}
}
return (TRUE);
}
/*
* Move the cursor forward by the specified number of words. As you move
* convert the first character of the word to upper case, and subsequent
* characters to lower case. Error if you try and move past the end of the
* buffer. Bound to "M-C".
*/
capword(f, n)
{
register int c;
if (n < 0)
return (FALSE);
while (n--) {
while (inword() == FALSE) {
if (forwchar(FALSE, 1) == FALSE)
return (FALSE);
}
if (inword() != FALSE) {
c = lgetc(curwp->w_dotp, curwp->w_doto);
if (c>='a' && c<='z') {
c -= 'a'-'A';
lputc(curwp->w_dotp, curwp->w_doto, c);
lchange(WFHARD);
}
if (forwchar(FALSE, 1) == FALSE)
return (FALSE);
while (inword() != FALSE) {
c = lgetc(curwp->w_dotp, curwp->w_doto);
if (c>='A' && c<='Z') {
c += 'a'-'A';
lputc(curwp->w_dotp, curwp->w_doto, c);
lchange(WFHARD);
}
if (forwchar(FALSE, 1) == FALSE)
return (FALSE);
}
}
}
return (TRUE);
}
/*
* Kill forward by "n" words. Remember the location of dot. Move forward by
* the right number of words. Put dot back where it was and issue the kill
* command for the right number of characters. Bound to "M-D".
*/
delfword(f, n)
{
register int size;
register LINE *dotp;
register int doto;
if (n < 0)
return (FALSE);
dotp = curwp->w_dotp;
doto = curwp->w_doto;
size = 0;
while (n--) {
while (inword() == FALSE) {
if (forwchar(FALSE, 1) == FALSE)
return (FALSE);
++size;
}
while (inword() != FALSE) {
if (forwchar(FALSE, 1) == FALSE)
return (FALSE);
++size;
}
}
curwp->w_dotp = dotp;
curwp->w_doto = doto;
return (ldelete(size, TRUE));
}
/*
* Kill backwards by "n" words. Move backwards by the desired number of words,
* counting the characters. When dot is finally moved to its resting place,
* fire off the kill command. Bound to "M-Rubout" and to "M-Backspace".
*/
delbword(f, n)
{
register int size;
if (n < 0)
return (FALSE);
if (backchar(FALSE, 1) == FALSE)
return (FALSE);
size = 0;
while (n--) {
while (inword() == FALSE) {
if (backchar(FALSE, 1) == FALSE)
return (FALSE);
++size;
}
while (inword() != FALSE) {
if (backchar(FALSE, 1) == FALSE)
return (FALSE);
++size;
}
}
if (forwchar(FALSE, 1) == FALSE)
return (FALSE);
return (ldelete(size, TRUE));
}
/*
* Return TRUE if the character at dot is a character that is considered to be
* part of a word. The word character list is hard coded. Should be setable.
*/
inword()
{
register int c;
if (curwp->w_doto == llength(curwp->w_dotp))
return (FALSE);
c = lgetc(curwp->w_dotp, curwp->w_doto);
if (c>='a' && c<='z')
return (TRUE);
if (c>='A' && c<='Z')
return (TRUE);
if (c>='0' && c<='9')
return (TRUE);
if (c=='$' || c=='_') /* For identifiers */
return (TRUE);
return (FALSE);
}